﻿Imports System
Imports System.Net
Imports System.IO
Imports System.IO.Packaging
Imports System.Printing
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Documents
Imports System.Windows.Input
Imports System.Windows.Markup
Imports System.Windows.Xps
Imports System.Windows.Xps.Packaging

Namespace ParitorWPF
    Class XPSDocumentViewer

        Private m_xpsDocumentPath As String             ' XPS document path and filename.
        Private m_packageUri As Uri                     ' XPS document path and filename URI.
        Private m_xpsPackage As Package = Nothing       ' XPS document package.
        Private m_xpsDocument As XpsDocument            ' XPS document within the package.
        Private m_xpsFixedDocumentSequence As FixedDocumentSequence

        Private ReadOnly _fixedDocumentSequenceContentType As String = "application/vnd.ms-package.xps-fixeddocumentsequence+xml"

        Public Sub New()

            ' This call is required by the Windows Form Designer.
            InitializeComponent()

            ' Add any initialization after the InitializeComponent() call.

        End Sub

        ' ------------------------------ OnOpen ------------------------------
        ''' <summary>
        '''   Handles the user "File | Open" menu operation.</summary>
        Public Sub OpenFile()
            ' If a document is currently open, check with the user
            ' if it's ok to close it before opening a new one.
            If m_xpsPackage IsNot Nothing Then
                CloseDocument()
            End If
            Dim dialog As New System.Windows.Forms.OpenFileDialog()
            dialog.InitialDirectory = GetContentFolder()
            dialog.Filter = "XPS Document files (*.xps)|*.xps|All files(*.*)|*.*"

            ' Show the "File Open" dialog.  If the user picks a file and
            ' clicks "OK", load and display the specified XPS document.
            If dialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
                OpenDocument(dialog.FileName)
            End If

        End Sub

        ''' --------------------------- OpenDocument ---------------------------
        ''' <summary>
        '''   Loads, displays, and enables user annotations
        '''   a given XPS document file.</summary>
        ''' <param name="filename">
        '''   The path and filename of the XPS document
        '''   to load, display, and annotate.</param>
        ''' <returns>
        '''   true if the document loads successfully; otherwise false.</returns>
        Public Function OpenDocument(ByVal filename As String) As Boolean
            ' Load an XPS document into a DocumentViewer
            ' and enable user Annotations.
            m_xpsDocumentPath = filename

            m_packageUri = New Uri(filename, UriKind.Absolute)
            Try
                m_xpsDocument = New XpsDocument(filename, FileAccess.ReadWrite)
            Catch generatedExceptionName As System.UnauthorizedAccessException
                Dim msg As String = filename + "" & Chr(10) & "" & Chr(10) & "The specified file is Read-Only which " + "prevents storing user annotations."
                MessageBox.Show(msg, "Read-Only file", MessageBoxButton.OK, MessageBoxImage.[Error])
                Return False
            Catch ex As Exception
                Dim msg As String = filename + "" & Chr(10) & "" & Chr(10) & ex.Message
                MessageBox.Show(msg, "File Error", MessageBoxButton.OK, MessageBoxImage.[Error])
                Return False
            End Try

            ' Get the document's PackageStore into which
            ' new user annotations will be added and saved.
            m_xpsPackage = PackageStore.GetPackage(m_packageUri)
            If (m_xpsPackage Is Nothing) OrElse (m_xpsDocument Is Nothing) Then
                MessageBox.Show("Unable to get Package from file.")
                Return False
            End If

            ' Get the FixedDocumentSequence from the open document.
            Dim fds As FixedDocumentSequence = m_xpsDocument.GetFixedDocumentSequence()
            If fds Is Nothing Then
                Dim msg As String = filename + "" & Chr(10) & "" & Chr(10) & "The document package within the specified " + "file does not contain a FixedDocumentSequence."
                MessageBox.Show(msg, "Package Error")
                Return False
            End If

            ' Load the FixedDocumentSequence to the DocumentViewer control.
            docViewer.Document = fds
            ' Enable user annotations on the document.
            Dim fixedDocumentSeqUri As Uri = GetFixedDocumentSequenceUri()

            ' Give the DocumentViewer focus.
            docViewer.Focus()
            Return True
        End Function
        ' ------------------------- GetContentFolder -------------------------
        ''' <summary>
        '''   Locates and returns the path to the "Content\" folder
        '''   containing the fixed document for the sample.</summary>
        ''' <returns>
        '''   The path to the fixed document "Content\" folder.</returns>
        ''' 
        Private Function GetContentFolder() As String
            ' Get the path to the current directory and its length.
            Dim contentDir As String = Directory.GetCurrentDirectory()
            Dim dirLength As Integer = contentDir.Length

            ' If we're in "...\bin\debug", move up to the root.
            If contentDir.ToLower().EndsWith("\bin\debug") Then
                contentDir = contentDir.Remove(dirLength - 10, 10)
            ElseIf contentDir.ToLower().EndsWith("\bin\release") Then
                contentDir = contentDir.Remove(dirLength - 12, 12)

                ' If we're in "...\bin\release", move up to the root.
            End If

            ' If there's a "Content" subfolder, that's what we want.
            If Directory.Exists(contentDir + "\Content") Then
                contentDir = contentDir + "\Content"
            End If

            ' Return the "Content\" folder (or the "current"
            ' directory if we're executing somewhere else).
            Return contentDir
        End Function
        ''' <summary>
        ''' Prints the Document
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Print(ByVal PrintTicket As PrintTicket)
            Dim dlg As New PrintDialog()

            ' Show the printer dialog.  If the return is "true",
            ' the user made a valid selection and clicked "Ok".
            dlg.PrintTicket = PrintTicket
            dlg.PrintQueue.DefaultPrintTicket = PrintTicket
            Select Case dlg.ShowDialog()
                Case True
                    Dim xpsdw As XpsDocumentWriter = PrintQueue.CreateXpsDocumentWriter(dlg.PrintQueue)
                    xpsdw.Write(m_xpsFixedDocumentSequence, dlg.PrintTicket)
            End Select

        End Sub

        ''' ------------------- GetFixedDocumentSequenceUri --------------------
        ''' <summary>
        '''   Returns the part URI of first FixedDocumentSequence
        '''   contained in the package.</summary>
        ''' <returns>
        '''   The URI of first FixedDocumentSequence in the package,
        '''   or null if no FixedDocumentSequence is found.</returns>
        Private Function GetFixedDocumentSequenceUri() As Uri
            ' Iterate through the package parts
            ' to find first FixedDocumentSequence.
            For Each part As PackagePart In m_xpsPackage.GetParts()
                If part.ContentType = _fixedDocumentSequenceContentType Then
                    Return part.Uri
                End If
            Next
            ' Return null if a FixedDocumentSequence isn't found.
            Return Nothing
        End Function

        ''' --------------------------- GetPackage -----------------------------
        ''' <summary>
        '''   Returns the XPS package contained within a given file.</summary>
        ''' <param name="filename">
        '''   The path and name of the file containing the package.</param>
        ''' <returns>
        '''   The package contained within the specifed file.</returns>
        Private Function GetPackage(ByVal filename As String) As Package
            Dim inputPackage As Package = Nothing

            ' "filename" should be the full path and name of the file.
            Dim webRequest As WebRequest = System.Net.WebRequest.Create(filename)
            If webRequest IsNot Nothing Then
                Dim webResponse As WebResponse = webRequest.GetResponse()
                If webResponse IsNot Nothing Then
                    Dim inputPackageStream As Stream = webResponse.GetResponseStream()
                    If inputPackageStream IsNot Nothing Then
                        ' Retreive the Package from that stream.
                        inputPackage = Package.Open(inputPackageStream)
                    End If
                End If
            End If

            Return inputPackage
        End Function

        ''' <summary>
        '''   Loads, displays, and enables user annotations
        '''   for a given XPS document stream.</summary>
        ''' <param name="xpsStream">
        '''   The memory stream of the XPS document
        '''   to load, display, and annotate.</param>
        ''' <returns>
        '''   true if the document loads successfully; otherwise false.</returns>
        Public Function OpenStream(ByVal xpsStream As MemoryStream) As Boolean

            If m_xpsPackage IsNot Nothing Then
                ' The user clicked OK, close the current document and continue.
                CloseDocument()
            End If

            m_xpsPackage = Package.Open(xpsStream)
            Dim packageUriString As String = "memorystream://inMemory" & Guid.NewGuid.ToString & ".xps"
            With m_xpsPackage

                Dim m_packageUri As Uri = New Uri(packageUriString)         ' Remember to create URI for the package
                PackageStore.AddPackage(m_packageUri, m_xpsPackage)         ' Need to add the Package to the PackageStore
                m_xpsDocument = New XpsDocument(m_xpsPackage, CompressionOption.SuperFast, packageUriString)
                '                                                           ' Create instance of XpsDocument 
                m_xpsFixedDocumentSequence = m_xpsDocument.GetFixedDocumentSequence
                Me.docViewer.Document = m_xpsFixedDocumentSequence


            End With
            Return True
        End Function

        ''' ------------------------ GetFixedDocument --------------------------
        ''' <summary>
        '''   Returns the fixed document at a given URI within
        '''   the currently open XPS package.</summary>
        ''' <param name="fixedDocUri">
        '''   The URI of the fixed document to return.</param>
        ''' <returns>
        '''   The fixed document at a given URI
        '''   within the current XPS package.</returns>
        Private Function GetFixedDocument(ByVal fixedDocUri As Uri) As FixedDocument
            Dim fixedDocument As FixedDocument = Nothing

            ' Create the URI for the fixed document within the package. The URI
            ' is used to set the Parser context so fonts & other items can load.
            Dim tempUri As New Uri(m_xpsDocumentPath, UriKind.RelativeOrAbsolute)
            Dim parserContext As New ParserContext()
            parserContext.BaseUri = PackUriHelper.Create(tempUri)

            ' Retreive the fixed document.
            Dim fixedDocPart As PackagePart = m_xpsPackage.GetPart(fixedDocUri)
            If fixedDocPart IsNot Nothing Then
                Dim fixedObject As Object = XamlReader.Load(fixedDocPart.GetStream(), parserContext)
                If fixedObject <> Nothing Then
                    fixedDocument = TryCast(fixedObject, FixedDocument)
                End If
            End If

            Return fixedDocument
        End Function


        Private Sub docViewer_Unloaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles docViewer.Unloaded
            CloseDocument()
        End Sub

        ''' <summary>
        '''   Closes the document currently displayed in
        '''   the DocumentViewer control.</summary>
        Public Sub CloseDocument()

            ' Remove the document from the DocumentViewer control.
            docViewer.Document = Nothing

            ' If the package is open, close it.
            If m_xpsPackage IsNot Nothing Then
                m_xpsPackage.Close()
                m_xpsPackage = Nothing
            End If

            If m_packageUri <> Nothing Then
                PackageStore.RemovePackage(m_packageUri)
            End If

        End Sub

    End Class

End Namespace
